import { expect } from 'chai';
import * as sinon from 'sinon';
import proxyquire from 'proxyquire';
import * as step from '@flow-step/step-toolkit'

describe('checkBranchBehind', () => {
    let envStub: sinon.SinonStub;
    let git: any;
    let simpleGitStub: sinon.SinonStub;
    let stepInfoStub: sinon.SinonStub;
    let stepErrorStub: sinon.SinonStub;
    let processExitStub: sinon.SinonStub;
    const workDir = './workspace';
    const myRepo = 'my-repo_LBTL';
    const sources = JSON.stringify([
        {
            name: myRepo,
            data: {},
        },
    ]);
    beforeEach(() => {
        envStub = sinon.stub(process, 'env')
            .value({'PROJECT_DIR': `${workDir}/${myRepo}`,
                'SOURCES': sources,
                'TARGET_BRANCH': 'master',
                'CI_COMMIT_REF_NAME': 'feature-branch',
                'CI_COMMIT_SHA': '123456'
            });
        stepInfoStub = sinon.stub(step, 'info');
        stepErrorStub = sinon.stub(step, 'error');
        git = {
            env: sinon.stub().resolves(),
            cwd: sinon.stub().resolves(),
            fetch: sinon.stub().resolves(),
            diff: sinon.stub().resolves('')
        }
        simpleGitStub = sinon.stub().returns(git);
        processExitStub = sinon.stub(process, 'exit');
    });

    afterEach(() => {
        sinon.restore();
    });

    it('should fetch and continue if branch is up to date or ahead', async () => {
        const checkBranchBehindProxy = proxyquire('../src/checkBranchBehind', {
            'simple-git': {simpleGit: simpleGitStub},
        }).checkBranchBehind;
        await checkBranchBehindProxy();


        expect(git.fetch.calledOnce).to.be.true;
        expect(git.diff.calledWithExactly(['HEAD...origin/master'])).to.be.true;
        expect(stepInfoStub.calledWithExactly('branch \'feature-branch\' is up to date with or ahead of \'master\', continue running.')).to.be.true;
        expect(processExitStub.notCalled).to.be.true;
    });

    it('should fetch and exit if branch is behind', async () => {
        git.diff.resolves("have diff")
        const checkBranchBehindProxy = proxyquire('../src/checkBranchBehind', {
            'simple-git': {simpleGit: simpleGitStub},
        }).checkBranchBehind;
        await checkBranchBehindProxy();

        expect(git.fetch.calledOnce).to.be.true;
        expect(git.diff.calledWithExactly(['HEAD...origin/master'])).to.be.true;
        expect(stepErrorStub.calledWithExactly('\'master\' has commits that \'feature-branch\' has not. Please merge \'master\' into \'feature-branch\' locally, push and rerun the pipeline.')).to.be.true;
        expect(stepInfoStub.calledWith("commit ID of branch 'feature-branch' is 123456")).to.be.true;
        expect(processExitStub.calledWithExactly(1)).to.be.true;
    });

    it('should handle fetch errors', async () => {
        git.fetch.rejects(new Error('Network Issue'))
        const checkBranchBehindProxy = proxyquire('../src/checkBranchBehind', {
            'simple-git': {simpleGit: simpleGitStub},
        }).checkBranchBehind;
        await checkBranchBehindProxy();

        expect(git.fetch.calledOnce).to.be.true;
        expect(stepErrorStub.calledWith(`git fetch failed: Network Issue`)).to.be.true;
        expect(git.diff.calledWithExactly(['HEAD...origin/master'])).to.be.true;
        expect(stepInfoStub.calledWithExactly('branch \'feature-branch\' is up to date with or ahead of \'master\', continue running.')).to.be.true;
        expect(processExitStub.notCalled).to.be.true;

    });

});

